package com.wdciti.sccp.iot.springvertx.factory;

import com.wdciti.sccp.iot.common.aio.DeployingException;
import com.wdciti.sccp.iot.common.aio.DeploymentResult;
import com.wdciti.sccp.iot.common.aio.HandlerDeploy;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Vertx;
import io.vertx.core.spi.VerticleFactory;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author by early
 */
@Slf4j
public abstract class AbstractVerticleFactory implements VerticleFactory, HandlerDeploy {

    @Getter
    protected Vertx vertx;

    protected DeploymentResult deploymentResult;

    protected int deployLatchAwaitTime = 5;    //全量部署时间
    protected TimeUnit deployLatchAwaitTimeUnit = TimeUnit.SECONDS;

    protected Map<String, DeploymentOptions> willDeploy = new HashMap<>();

    /**
     * call from Vertx when register this factory
     */
    @Override
    public void init(Vertx vertx) {
        this.vertx = vertx;
        this.deploymentResult = new DeploymentResult(prefix());
        VerticleFactory.super.init(vertx);
        log.info("VerticleFactory: [prefix:{}] initial...", prefix());
    }

    /**
     * hook on closing
     */
    @Override
    public void close() {
        vertx.unregisterVerticleFactory(this);
        VerticleFactory.super.close();
        log.info("VerticleFactory: [prefix:{}] closed!", prefix());
    }

    protected String verticleFullName(Object name) {
        return prefix() + ":" + name;
    }

    @Override
    public void deploy() throws DeployingException {
        CountDownLatch deployLatch = new CountDownLatch(willDeploy.size());
//        AtomicBoolean failed = new AtomicBoolean(false);  //初始设置是失败状态为否的状态
        for (String verticleName : willDeploy.keySet()) {
            vertx.deployVerticle(verticleName, willDeploy.get(verticleName), ar -> {
                if (ar.succeeded()) {
                    this.deploymentResult.addSuccessDeploy(verticleName, ar.result());
                    log.info("success deploy {}, verticle_id={}", verticleName, ar.result());
                } else {
                    log.error("Failed to deploy verticle", ar.cause());
                    this.deploymentResult.addFailedDeploy(verticleName, ar.cause());
//                    failed.compareAndSet(false, true);
                }
                deployLatch.countDown();
            });
        }
        try {
            if (!deployLatch.await(deployLatchAwaitTime, deployLatchAwaitTimeUnit)) {
                log.warn("Wait Timeout when verticle deploying ({} {})", deployLatchAwaitTime, deployLatchAwaitTimeUnit.name());
                throw new DeployingException("Wait Timeout when deploying");
//            } else if (failed.get()) { //单个出错暂时不抛出
//                throw new VerticleDeployingException("Failure Result for verticle deploying");
            }
        } catch (InterruptedException e) {
            throw new DeployingException("Thread Interrupted when verticle deploying", e);
        } finally {
//            this.deploymentResult.setSuccess(!failed.get());
            this.deploymentResult.setComplete(true);
        }
    }

    @Override
    public DeploymentResult getResult() {
        return this.deploymentResult;
    }
}
